package com.eralink.uhfreaderlib;

import java.util.Locale;

class Utils {
    public static byte bcc(byte[] data, int offset, int size) {
        byte ret = 0;
        for (int i = 0; i < size; ++i) {
            ret ^= data[offset + i];
        }
        return ret;
    }

    public static byte[] hexStrToBytes(String hexStr) {
        if (null == hexStr || hexStr.isEmpty() || (hexStr.length() % 2) != 0) {
            return new byte[0];
        }

        byte[] bytes = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; ++i) {
            bytes[i] = (byte) Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16);
        }

        return bytes;
    }

    private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
    public static String bytesToHexString(byte[] data, int offset, int size) {
        StringBuilder sb = new StringBuilder(size * 2);
        for (int i = 0; i < size; ++i) {
            sb.append(hexCode[(data[offset + i] >> 4) & 0xF]);
            sb.append(hexCode[(data[offset + i] & 0xF)]);
        }
        return sb.toString();
    }

    public static short calcEPCCRC(byte[] bytes, int offset, int len)
    {
        final int polynomial = 0x1021; // poly value
        int crc = 0xffff;

        for (int index = 0; index < len; ++index) {
            byte b = bytes[offset + index];
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b >> (7 - i) & 1) == 1);
                boolean c15 = ((crc >> 15 & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit)
                    crc ^= polynomial;
            }
        }

        crc &= 0xFFFF;

        return (short)crc;
    }

    public static Integer tryParseInt(String str) {
        Integer value;
        try {
            value = Integer.parseInt(str);
        } catch (Exception e) {
            value = null;
        }

        return value;
    }

    public static boolean parseInteger(String str, final int[] value) {
        if (str == null || value == null || value.length < 1) {
            return false;
        }

        try {
            value[0] = Integer.parseInt(str);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    public static boolean ipCheck(String text) {
        if (text != null && !text.isEmpty()) {
            // 定义正则表达式
            final String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
                    + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
                    + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
                    + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
            // 判断ip地址是否与正则表达式匹配
            if (text.matches(regex)) {
                // 返回判断信息
                return true;
            } else {
                // 返回判断信息
                return false;
            }
        }
        return false;
    }

    public static boolean isValidPort(String str_port) {
        final Integer port = tryParseInt(str_port);
        return port != null && 0 <= port && 65535 >= port;
    }

    public static short u16FromLittleEndianU8s(final byte[] buffer, int offset) {
        if (offset + 2 > buffer.length) {
            return 0;
        }

        return (short) ((buffer[offset] & 0xFF) | ((buffer[offset + 1] & 0xFF) << 8));
    }

    public static void u16ToLittleEndianU8s(short value, final byte[] buffer, int offset) {
        if (offset + 2 > buffer.length) {
            return;
        }

        buffer[offset] = (byte) value;
        buffer[offset + 1] = (byte) (value >> 8);
    }

    public static int u32FromLittleEndianU8s(final byte[] buffer, int offset) {
        if (offset + 4 > buffer.length) {
            return 0;
        }

        return (buffer[offset] & 0xFF) | ((buffer[offset + 1] & 0xFF) << 8) |
                ((buffer[offset + 2] & 0xFF) << 16) | ((buffer[offset + 3] & 0xFF) << 24);
    }

    public static void u32ToLittleEndianU8s(int value, final byte[] buffer, int offset) {
        if (offset + 4 > buffer.length) {
            return;
        }

        buffer[offset] = (byte) (value & 0xFF);
        buffer[offset + 1] = (byte) ((value >> 8) & 0xFF);
        buffer[offset + 2] = (byte) ((value >> 16) & 0xFF);
        buffer[offset + 3] = (byte) ((value >> 24) & 0xFF);
    }

    public static short u16FromBigEndianU8s(final byte[] buffer, int offset) {
        if (offset + 2 > buffer.length) {
            return -1;
        }

        return (short) (((buffer[offset] & 0xFF) << 8) | (buffer[offset + 1] & 0xFF));
    }

    public static void u16ToBigEndianU8s(short value, final byte[] buffer, int offset) {
        if (offset + 2 > buffer.length) {
            return;
        }
        buffer[offset] = (byte) ((value >> 8) & 0xFF);
        buffer[offset + 1] = (byte) (value & 0xFF);
    }

    public static int u32FromBigEndianU8s(final byte[] buffer, int offset) {
        if (offset + 4 > buffer.length) {
            return -1;
        }

        return ((buffer[offset] & 0xFF) << 24) | ((buffer[offset + 1] & 0xFF) << 16) |
                ((buffer[offset + 2] & 0xFF) << 8) | (buffer[offset + 3] & 0xFF);
    }

    public static void u32ToBigEndianU8s(int value, final byte[] buffer, int offset) {
        if (offset + 4 > buffer.length) {
            return;
        }

        buffer[offset] = (byte) ((value >> 24) & 0xFF);
        buffer[offset + 1] = (byte) ((value >> 16) & 0xFF);
        buffer[offset + 2] = (byte) ((value >> 8) & 0xFF);
        buffer[offset + 3] = (byte) (value & 0xFF);
    }

    public static String ipV4AddrFromU32(int address) {
        return String.format(Locale.getDefault(), "%d.%d.%d.%d", ((address >> 24) & 0xFF), ((address >> 16) & 0xFF),
                ((address >> 8) & 0xFF), address & 0xFF);
    }

    public static int ipV4AddrToU32(String ip) {
        if (!ipCheck(ip)) {
            return -1;
        }

        final String[] fields = ip.split("\\.");
        return (Integer.parseInt(fields[0]) << 24) | (Integer.parseInt(fields[1]) << 16) |
                (Integer.parseInt(fields[2]) << 8) | Integer.parseInt(fields[3]);
    }

    public static boolean bytesEqual(byte[] data1, int offset1, int len1, byte[] data2, int offset2, int len2) {
        assert (null != data1);
        assert (null != data2);

        if (len1 != len2) {
            return false;
        }

        for (int i = 0; i < len1; ++i) {
            if (data1[offset1 + i] != data2[offset2 + i]) {
                return  false;
            }
        }

        return true;
    }
}
